package com.fucking.great.context.manager;

import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.fucking.great.context.exception.TxnRuntimeException;
import com.fucking.great.context.config.PathConfigBean;
import com.fucking.great.context.config.SystemConfigBean;
import com.fucking.great.context.config.TxnConfiger;
import com.fucking.great.context.plun.Plug;

import java.util.*;

/**
 * 组件管理者: <br/>
 * 用于管理组件在处理周期内, 所有插件的 init begin commit rollback
 */
public class PlugManager {
    public static final Log log = LogFactory.get();
    /**
     * 组件集合
     */
    private List<Plug> plugList;
    /**
     * 初始化过的组件名.
     */
    private final Set<String> initPlunNameSet = new HashSet<>();
    /**
     * 所有需要导包的名称
     */
    private final Set<String> importAllSet = new HashSet<>();
    /**
     * 组件实例Map
     */
    private final Map<String, Object> plunInstanceMap = new HashMap<>();
    /** 允许初始化 */
    private boolean allowInit = true;
    /** 允许开始 */
    private boolean allowBegin = true;
    /** 允许提交 */
    private boolean allowCommit = true;
    /** 允许回滚 */
    private boolean allowRollaback = true;


    public List<Plug> initPlug(SystemConfigBean systemConfigBean, PathConfigBean pathConfigBean,  TxnConfiger txnConfinger) {
        if(isAllowInit()){
            //
            String systemName = systemConfigBean.getSystemName();
            String[] pluns = pathConfigBean.getPluns();
            // 一般只初始化一下，这样防止list扩容。
            if(this.plugList == null){
                this.plugList = new ArrayList<>(pluns.length);
            }
            //
            for (String plunName : pluns) {
                Set<String> imports;
                // 包含了就不再初始化。
                if (!initPlunNameSet.contains(plunName)) {
                    // plug
                    Plug plug = txnConfinger.getPlug(plunName, systemName);
                    if (plug == null) {
                        continue;
                    }
                    this.initPlunNameSet.add(plunName);
                    this.plugList.add(plug);
                    //  导包需要
                    imports = plug.importStr();
                    importAllSet.addAll(imports);
                    // 在这里开始事务。
                    Map<String, Object> plunMap = plug.beginUser();
                    plunInstanceMap.putAll(plunMap);
                }
            }
        }
        return this.plugList;
    }

    public Map<String, Object> beginUser(List<Plug> PlugList) {
        if(isAllowBegin()){
            Map<String, Object> plunMap;
            for (Plug plug : PlugList) {
                if(!this.plugList.contains(plug)){
                    plunMap = plug.beginUser();
                    plunMap.entrySet().forEach(x -> {
                        String key = x.getKey();
                        if (this.plunInstanceMap.putIfAbsent(key,x.getValue()) != null) {
                            TxnRuntimeException.throwException("SYS_GREAT_PLUN_BEGIN_INSTANCE_REPEAT",
                                    StrUtil.format("插件列表begin过程,实例名[{}]重复,请检查配置和扩展插件工厂",key));
                        }
                    });
                }
            }
        }
        return plunInstanceMap;
    }



    public void commit(List<Plug> PlugList) {
        if(isAllowCommit()){
            PlugList.forEach((plug) -> {
                try {
                    plug.commit();
                } catch (Exception e) {
                    // 忽略错误.
                    log.info(e, "commit,异常请核查一下系统组件是否有处理异常");
                }
            });
        }
    }

    public void quietRollback(List<Plug> PlugList) {
        if(isAllowRollaback()){
            PlugList.forEach((plug) -> {
                try {
                    plug.quietRollback();
                } catch (Exception e) {
                    // 忽略错误.
                    log.info(e, "quietRollback,异常请核查一下系统组件是否有处理异常");
                }
            });
        }
    }



    /////////////////////////////////////////////////
    ////
    /////////////////////////////////////////////////


    public Map<String, Object> getPlunInstanceMap() {
        return plunInstanceMap;
    }

    public Set<String> getInitPlunNameSet() {
        return initPlunNameSet;
    }

    public boolean isAllowInit() {
        return allowInit;
    }

    public void setAllowInit(boolean allowInit) {
        this.allowInit = allowInit;
    }

    public boolean isAllowBegin() {
        return allowBegin;
    }

    public void setAllowBegin(boolean allowBegin) {
        this.allowBegin = allowBegin;
    }

    public boolean isAllowCommit() {
        return allowCommit;
    }

    public void setAllowCommit(boolean allowCommit) {
        this.allowCommit = allowCommit;
    }

    public boolean isAllowRollaback() {
        return allowRollaback;
    }

    public void setAllowRollaback(boolean allowRollaback) {
        this.allowRollaback = allowRollaback;
    }

    public List<Plug> getPlugList() {
        return plugList;
    }

    public Set<String> getImportAllSet() {
        return importAllSet;
    }
}
